package emulator.shell.GUI.graph;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.ArrayList;
import java.util.LinkedList;

import javax.swing.JPanel;

@SuppressWarnings("serial")
public class BitGraph extends JPanel
{
	private static final int PREFERRED_WIDTH = 400;
	private static final int PREFERRED_HEIGHT = 600;
	private static final int BORDER_GAP_LEFT 	= 40;
	private static final int BORDER_GAP_RIGHT 	= 30;
	private static final int BORDER_GAP_TOP 	= 20;
	private static final int BORDER_GAP_BOTTOM 	= 50;
	private static final int LINE_GAP = 10;
	private BitGraphLine [] graphLines;
	private long tickBegin = 0;
	private long tickEnd = 0;
	private int scalesSteps = 1;
	
	public BitGraph(int lineCount)
	{
		graphLines = new BitGraphLine [lineCount];
		for (int i = 0; i < graphLines.length; i++)
			graphLines[i] = new BitGraphLine();
	}

	@Override
	protected void paintComponent(Graphics g)
	{
		super.paintComponent(g);

	    Graphics2D g2 = (Graphics2D)g;
	    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        FontMetrics fontMetrics = getFontMetrics(g2.getFont());

	    int maxIndex = 0;
		for (int i = 0; i < graphLines.length; i++)
			if (graphLines[i].getPositionIndex() > maxIndex)
				maxIndex = graphLines[i].getPositionIndex();
	    
		int lineCount = maxIndex + 1;
		ArrayList<LinkedList<BitGraphLine>> labelLineStack = new ArrayList<LinkedList<BitGraphLine>> (lineCount);
		for (int i = 0; i < lineCount; i++)
			labelLineStack.add(new LinkedList<BitGraphLine>());
		for (int i = 0; i < graphLines.length; i++)
			labelLineStack.get(graphLines[i].getPositionIndex()).add(graphLines[i]);
		
		int width = getWidth() - BORDER_GAP_LEFT - BORDER_GAP_RIGHT;
		int height = getHeight() - BORDER_GAP_TOP - BORDER_GAP_BOTTOM;
		double lineHeight = (double)(height - maxIndex*LINE_GAP) / lineCount;
		
		// axes + labels
		g2.setColor(Color.white);
		g2.fillRect(BORDER_GAP_LEFT, BORDER_GAP_TOP-LINE_GAP, width, height+2*LINE_GAP);
		g2.setColor(Color.black);
		g2.drawRect(BORDER_GAP_LEFT, BORDER_GAP_TOP-LINE_GAP, width, height+2*LINE_GAP);
		for (int i = 0; i < lineCount; i++)
		{
			if (labelLineStack.get(i).size() > 0)
			{
				double y1 = BORDER_GAP_TOP + i * (lineHeight + LINE_GAP);
				double yd = lineHeight / labelLineStack.get(i).size();
				for (int j = 0; j < labelLineStack.get(i).size(); j++)
				{
					g2.setColor(labelLineStack.get(i).get(j).getColor());
					g2.drawString(labelLineStack.get(i).get(j).getLabel(), 5, (int)(y1+yd*(j+1)));
				}
			}
		}
		scalesSteps = width / fontMetrics.stringWidth("000000000");
		if (tickEnd > tickBegin && scalesSteps > 0)
		{
			if (scalesSteps > (tickEnd - tickBegin))
				scalesSteps = (int) (tickEnd - tickBegin);
			int scalesBaseLine = BORDER_GAP_TOP + height + 2 * LINE_GAP + fontMetrics.getHeight();
			for (int i = 0; i < scalesSteps+1; i++)
			{
				String scaleText = "" + (tickEnd - (tickEnd - tickBegin)*(scalesSteps-i)/scalesSteps);
				int xm = BORDER_GAP_LEFT + width*i/scalesSteps;
				int textWidth = fontMetrics.stringWidth(scaleText);
				g2.drawString(scaleText, xm - textWidth/2, scalesBaseLine);
				g2.drawLine(xm, BORDER_GAP_TOP-LINE_GAP, xm, BORDER_GAP_TOP + height + LINE_GAP);
			}
		}
		
		// graph lines
		for (int i = 0; i < graphLines.length; i++)
		{
			graphLines[i].draw(g2, tickBegin, tickEnd, BORDER_GAP_LEFT, BORDER_GAP_TOP, LINE_GAP, width, lineHeight);
		}
	}

	@Override
	public Dimension getPreferredSize() 
	{
		return new Dimension(PREFERRED_WIDTH, PREFERRED_HEIGHT);
	}

	public BitGraphLine getGraphLine(int i)
	{
		return graphLines[i];
	}
	
	public void setRange(long tickBegin, long tickEnd)
	{
		this.tickBegin = tickBegin;
		this.tickEnd = tickEnd;
	}
	
	public long getRange()
	{
		return tickEnd - tickBegin;
	}

	public int getScalesSteps()
	{
		return scalesSteps;
	}
}
